package com.hobart.learning.lagou.edu.IPersistence.utils;


import org.apache.commons.lang3.StringUtils;

/**
 * @author ：hobart
 * @date ：Created in 2020-11-11 1:17
 * @description：标记处理
 * @modified By：
 * @version: 1$
 */
public class GenericTokenParser {

    private final String openToken; // 开始标记
    private final String closeToken; // 结束标记
    private final TokenHandler tokenHandler; // 标记处理

    public GenericTokenParser(String openToken, String closeToken, TokenHandler tokenHandler) {
        this.openToken = openToken;
        this.closeToken = closeToken;
        this.tokenHandler = tokenHandler;
    }

    /**
     * 解析#{}和${}
     *
     * 该方法主要实现了配置文件、脚本等片段中止占位符的解析，
     * 处理工作，并返回最终需要的数据。
     * 其中，解析工作由该方法完成，处理工作由处理器handler的
     * handlerToken() 方法实现
     * @param sql
     * @return
     */
    public String parse(String sql) {
        // 验证参数是否有问题，
        if(StringUtils.isEmpty(sql)){
            return "";
        }

        // 下面继续验证是否包含开始标签，如果不包含，默认不是占位符，直接原样返回即可，否则继续处理

        int start = sql.indexOf(openToken, 0);

        if(start == -1){
            return sql;
        }

        // 把sql 转成 字符串数数组src,并定义默认偏移量offset=0,
        // 存储 最终需要返回的字符串的变量builder,
        // text 变量中占位符 对应的变量名 expression.
        // 判断start 是否大于（即text中是否存在 openToken）,
        // 如果存在就继续执行下面代码
        char[] src = sql.toCharArray();
        int offset = 0;
        final StringBuilder builder = new StringBuilder();
        StringBuilder expression = null;
        while (start > -1) {
            // 判断如果开始标记前如果有转移字符，就不作为openToken
            // 进行处理，否则继续处理
            if(start > 0 && src[start -1] =='\\'){
                builder.append(src,offset, start - offset - 1).append(openToken);
                offset = start + openToken.length();
            } else {
                // 重置express 变量，避免空指针或者老数据干扰。
                if(expression == null) {
                    expression = new StringBuilder();
                } else {
                    expression.setLength(0);
                }
                builder.append(src, offset, start - offset);
                offset = start + openToken.length();
                int end = sql.indexOf(closeToken, offset);
                while (end > -1) {
                    if(end > offset && src[end-1] == '\\') {
                        // 如果结束标记前面有转义字符时
                        // this close token is escaped. remove the backslash and continue.
                        expression.append(src, offset, end - offset -1).append(closeToken);
                        offset = end + closeToken.length();
                        end = sql.indexOf(closeToken, offset);
                    } else {
                        expression.append(src, offset,  end - offset);
                        offset = end + closeToken.length();
                        break;
                    }
                }
                if(end == -1){
                    // close token was not found
                    builder.append(src, start, src.length - start);
                    offset  = src.length;
                } else {
                    // 首先根据参数的key（即expression）进行参数处理，返回？作为占位符
                    builder.append(tokenHandler.handleToken(expression.toString()));
                    offset = end + closeToken.length();
                }
            }
            start = sql.indexOf(openToken, offset);
        }
        if(offset < src.length){
            builder.append(src, offset, src.length - offset);
        }

        return builder.toString();
    }
}
